﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.BusinessObjects.Providers;
using System.BusinessObjects.Data;

namespace Blazing.WebFacade
{
    public static class FacadeCacheManager
    {
        public static CacheProvider Cache
        {
            get { return System.BusinessObjects.Providers.CacheProvider.Provider; }
        }

        /// <summary>
        /// Attempts to fetch target object from cache, if this fails the LoadAction delegate is called to fetch the object 
        /// from the db
        /// </summary>
        public static T GetItem<T, TIdType>(Func<TIdType, T> loadAction, TIdType objId, ref object syncObj, string cacheKey)
        {
            string rcacheKey = CacheProvider.CreateCacheString(typeof(T).FullName, cacheKey);
            T item = Cache.GetCache<T>(rcacheKey);
            if (item == null)
            {
                lock (syncObj)
                {
                    item = Cache.GetCache<T>(rcacheKey);
                    if (item == null)
                    {
                        item = loadAction(objId);
                        if (item != null)
                        {
                            Cache.SetCache(rcacheKey, item);
                        }
                    }
                }
            }
            return item;
        }

        /// <summary>
        /// Attempts to fetch target object from cache, if this fails the LoadAction delegate is called to fetch the object 
        /// from the db
        /// </summary>
        public static T GetItem<T, TIdType>(Func<TIdType, T> loadAction, TIdType objId, ref object syncObj, params object[] cacheKeys)
        {
            string cacheKey = CacheProvider.CreateCacheString("", cacheKeys);
            return GetItem<T, TIdType>(loadAction, objId, ref syncObj, cacheKey);
        }

        /// <summary>
        /// GetItem works in two parts, LoadActionID stored the object id for the query, LoadActionObject loads the actual object from its id.
        /// This way LoadActionObject can reference the actual object's cache.
        /// </summary>
        public static T GetItemCache<T>(Func<int> loadActionID, Func<int, T> loadActionObject, ref object syncObj, string cacheKey) where T : DataObject
        {
            string rcacheKey = CacheProvider.CreateCacheString(typeof(T).FullName, cacheKey);
            int? itemId = Cache.GetCache<int?>(rcacheKey);
            T item = null;

            if (itemId == null || itemId == 0)
            {
                lock (syncObj)
                {
                    itemId = Cache.GetCache<int?>(rcacheKey);
                    if (itemId == null || itemId == 0)
                    {
                        itemId = loadActionID();
                        if (itemId != null)
                        {
                            Cache.SetCache(rcacheKey, itemId);
                        }
                    }
                }
            }
            if (itemId != null)
            {
                item = loadActionObject(itemId.Value);
            }

            return item;
        }

        /// <summary>
        /// GetItem works in two parts, LoadActionID stored the object id for the query, LoadActionObject loads the actual object from its object cache, in effect we only need to keep 1 copy of the target object.
        /// This way LoadActionObject can reference the actual object's cache.
        /// </summary>
        public static T GetItemCache<T>(Func<int> loadActionID, Func<int, T> loadActionObject, ref object syncObj, params object[] cacheKeys) where T : DataObject
        {
            string cacheKey = CacheProvider.CreateCacheString("", cacheKeys);
            return GetItemCache<T>(loadActionID, loadActionObject, ref syncObj, cacheKey);
        }

        public static void Invalidate<T>(string cacheKey)
        {
            string rcacheKey = CacheProvider.CreateCacheString(typeof(T).FullName, cacheKey);
            Cache.RemoveCache(rcacheKey);
        }

        public static void Invalidate<T>(params object[] cacheKeys)
        {
            string cacheKey = CacheProvider.CreateCacheString("", cacheKeys);
            Invalidate<T>(cacheKey);
        }
    }
}
